package com.dmxrow;

import com.Properties;
import com.swingson.SwingsonGuiBuilder;
import com.universe.Universe;
import com.universe.Wheel;
import com.universe.WheelList;
import com.utils.Utils;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;

/**
 * @author sad
 */
public class MainWindow extends JFrame {

    private final Universe universe0 = new Universe();
    private final Universe universe1 = new Universe();
    private final Universe universe2 = new Universe();
    private final Universe universe3 = new Universe();
    private final Universe universe4 = new Universe();
    private final Universe universe5 = new Universe();
    private final Universe[] universes = new Universe[6];

    public MainWindow() throws Exception {
        //System.setErr(new PrintStream("./err_"+Properties.profile.getName()+".txt"));
        //System.setOut(new PrintStream("./out_"+Properties.profile.getName()+".txt"));
        setTitle("DmxEmulator " + Properties.profile.getName() + "  Port " + Properties.profile.getPort());
        SwingsonGuiBuilder.createGuiFromJsonInPackage(this);
        universes[0] = universe0;
        universes[1] = universe1;
        universes[2] = universe2;
        universes[3] = universe3;
        universes[4] = universe4;
        universes[5] = universe5;
        int i = Properties.profile.getRow() * 6;
        int index = 0;
        for (Universe u : universes) {
            u.setWindow(this);
            u.setUniverseIndex(i);
            u.setToolTipText("Universe " + i);
            WheelList wl = Properties.profile.getWheels();
            if (wl != null) {
                Wheel wheel = wl.getWheelForUniverse(i);
                if (wheel != null) {
                    u.setWheel(wheel);
                }
            }

            i++;
            index++;
        }

        for (Universe u : universes) {
            u.createPixelMapping();
            u.recalculateMasks();
        }

        startServer();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setResizable(false);
    }

    public void startServer() throws SocketException {
        final DatagramSocket server = new DatagramSocket(Properties.profile.getPort());
        System.out.println("Server started at port " + Properties.profile.getPort());
        Thread thread = new Thread() {

            @Override
            public void run() {
                DatagramPacket packet = new DatagramPacket(new byte[100000], 100000);
                while (true) {
                    try {
                        server.receive(packet);
                        parseReceived(packet.getData(), packet.getLength());
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        };

        thread.start();
    }

    private void parseReceived(byte[] data, int length) {
        byte[] magic;
        try {
            magic = "Art-Net ".getBytes("Cp1251");
        } catch (UnsupportedEncodingException ex) {
            throw new RuntimeException(ex);
        }

        magic[7] = 0;
        for (int i = 0; i < 8; i++) {
            if (magic[i] != data[i]) {
                throw new BadPacketException("Wrong packet magic number");
            }
        }

        int opcode = Utils.lhTo16Bit(data[8], data[9]);
        if (opcode != 0x5000) {
            throw new BadPacketException("Wrong opcode");
        }

        int protocol = Utils.lhTo16Bit(data[11], data[10]);
        if (protocol != 14) {
            throw new BadPacketException("Wrong protocol. Need 14 found" + protocol);
        }

        int secuence = Utils.unsignedByte(data[12]);
        int physical = Utils.unsignedByte(data[13]);
        final int fullDmxAddress = Utils.lhTo16Bit(data[14], data[15]);
        final int dataLength = Utils.lhTo16Bit(data[17], data[16]);
        final byte[] picsData = new byte[dataLength];
        System.arraycopy(data, 18, picsData, 0, dataLength);
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                showUniverse(picsData, dataLength, fullDmxAddress);
            }
        });

    }

    public void showUniverse(byte[] data, int dataLength, int address) {
        int net = (address / 16);
        int universeIndex = address - (16 * net);
        if (!(universeIndex >= 0 && universeIndex < universes.length)) {
            throw new BadPacketException("Cannot process universe " + universeIndex);
        }

        Universe universe = universes[universeIndex];
        universe.setData(data);
    }
}
